unit buffer;

interface

uses
  common, IdGlobal, System.sysUtils, System.Generics.Collections;

type
  TBuffer = record
    index: int32;
    t: uint64;
    l: int32;
    data: TIdBytes;
  end;

var
  buffers: TThreadList<TBuffer>;
  tagMax: uint64;

function readBuffer(sliceIndex: int32; var data: TIdBytes;
  var len: int32): boolean;

function queryBufferItem(sliceIndex: int32): int32;

function selectBufferItem: int32;

procedure writeBuffer(sliceIndex: int32; data: TIdBytes; len: int32);

implementation

function readBuffer(sliceIndex: int32; var data: TIdBytes;
  var len: int32): boolean;
begin
  var
  i := queryBufferItem(sliceIndex);
  var
  b := buffers.LockList;
  result := i <> -1;
  if result then
  begin
//    SetLength(data, b[i].l);
    CopyTIdBytes(b[i].data, 0, data, 0, b[i].l);
    len := b[i].l;
  end;
  buffers.unlocklist;
end;

function queryBufferItem(sliceIndex: int32): int32;
begin
  result := -1;
  var
  b := buffers.LockList;
  for var i := 0 to b.count - 1 do
  begin
    if b[i].index = sliceIndex then
    begin
      result := i;
      break;
    end;
  end;
  buffers.unlocklist;
end;

function selectBufferItem: int32;
begin
  result := -1;
  var
  k := 0;
  var
  b := buffers.LockList;
  for var i := 0 to b.count - 1 do
  begin
    if tagMax - b[i].t > k then
    begin
      result := i;
      k := tagMax - b[i].t;
    end;
  end;
  buffers.unlocklist;
end;

procedure writeBuffer(sliceIndex: int32; data: TIdBytes; len: int32);
begin
  if queryBufferItem(sliceIndex) = -1 then
  begin
    var
      buf: TBuffer;
    buf.t := tagMax;
    inc(tagMax);
    buf.l := len;
    buf.index := sliceIndex;
    SetLength(buf.data, len);
    CopyTIdBytes(data, 0, buf.data, 0, len);
    var
    b := buffers.LockList;
    if b.count < bufferLength then
      buffers.Add(buf)
    else
    begin
      var
      i := selectBufferItem;
      b[i] := buf;
    end;
    buffers.unlocklist;
  end;
end;

initialization

buffers := TThreadList<TBuffer>.Create;
tagMax := 0;

end.
